package com.vision.utils;

import com.aliyun.oss.*;
import com.aliyun.oss.internal.Mimetypes;
import com.aliyun.oss.model.*;
import com.aliyun.sts20150401.models.AssumeRoleRequest;
import com.aliyun.sts20150401.models.AssumeRoleResponse;
import com.aliyun.tea.*;
import com.aliyun.sts20150401.Client;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.*;

/**
 * 阿里云 Oss 对象存储 api
 * 1. 引入依赖
 * <dependency>
 *     <groupId>com.aliyun.oss</groupId>
 *     <artifactId>aliyun-sdk-oss</artifactId>
 *     <version>3.15.1</version>
 * </dependency>
 */
@Component
public class AliOssUtil {

    private static final String END_POINT = "oss-cn-beijing.aliyuncs.com";// 2. 填写 endpoint
    private static final String ACCESS_KEY_ID = "";// 3. 填写 AccessKey
    private static final String ACCESS_KEY_SECRET = "";// 4. 填写 AccessSecret
    private static final String BUCKET_NAME = "escapeicon-big-event";// 5. 填写容器名

    /**
     * 6. 调用方法
     * @param objectName 存储对象名
     * @return 阿里云远程服务地址
     * @throws Exception 异常
     */
    public static String uploadFile(String objectName, String filePath) throws Exception {

        // 创建OSSClient实例。
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        // 设置OSSClient允许打开的最大HTTP连接数，默认为1024个。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(END_POINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET, conf);

        String url = "";

        try {
            // 创建InitiateMultipartUploadRequest对象。
            InitiateMultipartUploadRequest initiateRequest = new InitiateMultipartUploadRequest(BUCKET_NAME, objectName);

            // 初始化分片
            ObjectMetadata metadata = new ObjectMetadata();

            if (metadata.getContentType() == null) {
                metadata.setContentType(Mimetypes.getInstance().getMimetype(objectName));
            }

            // 初始化分片。
            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(initiateRequest);
            String uploadId = upresult.getUploadId();

            // partETags是PartETag的集合。
            List<PartETag> partETags =  new ArrayList<>();

            // 每个分片的大小，用于计算文件有多少个分片。单位为字节。
            final long partSize = 1024 * 1024L;   //1 MB。

            // 根据上传的数据大小计算分片数。
            final File file = new File(filePath);
            long fileLength = file.length();
            int partCount = (int) (fileLength / partSize);
            if (fileLength % partSize != 0) {
                partCount++;
            }

            // 遍历分片上传。
            for (int i = 0; i < partCount; i++) {
                long startPos = i * partSize;
                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
                UploadPartRequest uploadPartRequest = new UploadPartRequest();
                uploadPartRequest.setBucketName(BUCKET_NAME);
                uploadPartRequest.setKey(objectName);
                uploadPartRequest.setUploadId(uploadId);

                InputStream instream = new FileInputStream(file);
                instream.skip(startPos);
                // 设置上传的分片流。
                uploadPartRequest.setInputStream(instream);

                // 设置分片大小。
                uploadPartRequest.setPartSize(curPartSize);

                // 设置分片号。
                uploadPartRequest.setPartNumber(i + 1);

                // 上传分片。
                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);

                // 每次上传分片之后，OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
                partETags.add(uploadPartResult.getPartETag());
            }

            // 创建CompleteMultipartUploadRequest对象。
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(BUCKET_NAME, objectName, uploadId, partETags);

            // 完成分片上传。
            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);

            // 拼接上传到 oss 的文件 url
            // https:// 同名 . endpoint / file 文件名
            url = "https://" + BUCKET_NAME + "." + END_POINT + "/" + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return url;
    }

    /**
     * 删除文件
     * @param url 文件 url
     * @throws Exception 异常
     */
    public static void deleteFile(String url) throws Exception {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(END_POINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        // https://escapeicon-big-event.oss-cn-beijing.aliyuncs.com/cover/1.jpg
        url = url.replace("https://" + BUCKET_NAME + "." + END_POINT + "/", "");

        try {
            // 删除文件或目录。如果要删除目录，目录必须为空。
            ossClient.deleteObject(BUCKET_NAME, url);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 使用AK&SK初始化账号Client
     * @param accessKeyId    AccessKeyId
     * @param accessKeySecret   AccessKeySecret
     * @return Client
     * @throws Exception 异常
     */
    public static Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
                // 必填，您的 AccessKey ID
                .setAccessKeyId(accessKeyId)
                // 必填，您的 AccessKey Secret
                .setAccessKeySecret(accessKeySecret);
        // Endpoint 请参考 https://api.aliyun.com/product/Sts
        config.endpoint = "sts.cn-beijing.aliyuncs.com";
        return new Client(config);
    }

    public static AssumeRoleResponse getAssumeRoleResponse() throws Exception {
        Client client = createClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET);

        AssumeRoleRequest assumeRoleRequest = new AssumeRoleRequest();
        assumeRoleRequest.setRoleArn("acs:ram::1287099531035768:role/visionoss");
        assumeRoleRequest.setDurationSeconds(1000L);
        assumeRoleRequest.setRoleSessionName("visionoss");
        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
        try {
            // 复制代码运行请自行打印 API 的返回值
            return client.assumeRoleWithOptions(assumeRoleRequest, runtime);
        } catch (TeaException error) {
            // 错误 message
            System.out.println(error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // 错误 message
            System.out.println(error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            com.aliyun.teautil.Common.assertAsString(error.message);
        }
        return null;
    }

}
